package com.company.graph;

import java.util.*;

public class NopowerNoDirectEdgeWithNodeGraph implements EdgeGraph {
    private HashMap<Integer, List<PowerEdge>> adjs;
    private HashMap<Integer, HashMap<Integer, PowerEdge>> v_adjs;
    private HashMap<Integer, PowerEdge> id_adjs;
    private int edgeTotal = 0;

    public NopowerNoDirectEdgeWithNodeGraph() {
        adjs = new HashMap<>();
        v_adjs = new HashMap<>();
        id_adjs = new HashMap<>();
    }

    /**
     * v represents the node v
     * w represents the node w
     * the edge is  "v - w"
     */
    @Override
    public void addEdge(int v, int w) {
        addEdge(v, w, 0);
    }

    @Override
    public void addEdge(int v, int w, double power) {
        if (v == w) {
            return;
        }
        List<PowerEdge> vEdges = getListById(v);
        List<PowerEdge> wEdges = getListById(w);
        HashMap<Integer, PowerEdge> vMap = getSetById(v);
        HashMap<Integer, PowerEdge> wMap = getSetById(w);
        if (getEdge(v, w) == null) {
            PowerEdge edge = new PowerEdge(v, w, power);
            vEdges.add(edge);
            wEdges.add(edge);
            vMap.put(w, edge);
            wMap.put(v, edge);
            id_adjs.put(edge.getId(), edge);
            edgeTotal++;
        }
    }

    private HashMap<Integer, PowerEdge> getSetById(int v) {
        HashMap<Integer, PowerEdge> map;
        if (v_adjs.containsKey(v)) {
            map = v_adjs.get(v);
        } else {
            map = new HashMap<>();
            v_adjs.put(v, map);
        }
        return map;
    }

    private List<PowerEdge> getListById(int id) {
        List<PowerEdge> edges;
        if (adjs.containsKey(id)) {
            edges = adjs.get(id);
        } else {
            edges = new LinkedList<>();
            adjs.put(id, edges);
        }
        return edges;
    }


    @Override
    public String display() {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<Integer, List<PowerEdge>> entry : adjs.entrySet()) {
            Integer v = entry.getKey();
            sb.append(v);
            sb.append(' ');
            List<PowerEdge> list = entry.getValue();
            for (PowerEdge edge : list) {
                sb.append(edge.other(v));
                sb.append(' ');
            }
            sb.append('\n');
        }
        return sb.toString();
    }

    @Override
    public Integer E() {
        return edgeTotal;
    }

    @Override
    public List<PowerEdge> adjectives() {
        List<PowerEdge> list = new LinkedList<>();
        for (Map.Entry<Integer, PowerEdge> entry : this.id_adjs.entrySet()) {
            list.add(entry.getValue());
        }
        return list;
    }

    @Override
    public List<PowerEdge> adj(Integer v) {
        return this.adjs.get(v);
    }

    @Override
    public PowerEdge getEdge(int v, int w) {
        return v_adjs.get(v).get(w);
    }

    @Override
    public int nodeLength() {
        return adjs.size();
    }

    public PowerEdge getEdgeById(int edgeId) {
        return id_adjs.get(edgeId);
    }

    public List<PowerEdge> getRelatedEdges(int edgeId) {
        PowerEdge edgeVW = id_adjs.get(edgeId);
        if (edgeVW == null) {
            return null;
        }
        List<PowerEdge> answer = new ArrayList<>();
        int v = edgeVW.getV();
        int w = edgeVW.getW();
        List<PowerEdge> powerEdges = adj(v);
        for (PowerEdge edgeVP : powerEdges) {
            //找出关联边“v-p”
            if (edgeVW == edgeVP) {
                //找出的关联边中，不可以包括自身这条“v-w”
                continue;
            }
            int p = edgeVP.other(v);
            //检查是否存在"p-w"，如果有，说明构成了三角形
            PowerEdge edgePW = getEdge(p, w);
            if (edgePW == null) {
                continue;
            }
            //这些边都是可行的
            answer.add(edgeVP);
            answer.add(edgePW);
        }
        return answer;
    }

    @Override
    public void deleteEdge(int v, int w) {
        List<PowerEdge> vList = getListById(v);
        List<PowerEdge> wList = getListById(w);
        HashMap<Integer, PowerEdge> vMap = getSetById(v);
        HashMap<Integer, PowerEdge> wMap = getSetById(w);
        PowerEdge powerEdge = getEdge(v, w);
        id_adjs.remove(powerEdge.getId());
        vList.remove(powerEdge);
        wList.remove(powerEdge);
        vMap.remove(w);
        wMap.remove(v);
    }

    public boolean deleteEdgeById(int edgeID) {
        PowerEdge edge = id_adjs.get(edgeID);
        if (edge == null) {
            return false;
        }
        int v = edge.getV();
        int w = edge.getW();
        deleteEdge(v, w);
        return true;
    }
}
